﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace St0rm.IRCPro.Client {

    

    /// <summary>
    /// Represents an IRC user
    /// </summary>
    public class User {
        private string _nick, _user, _host;
        private Client _client = null;
        private static Dictionary<Client, User> mes = new Dictionary<Client, User>();
        /// <summary>
        /// Gets and sets the user's nickname
        /// </summary>
        public string Nick {
            get {
                return _nick;
            }
            set {
                _nick = value;
            }
        }
        /// <summary>
        /// Gets the Client this user is on
        /// </summary>
        public Client Client {
            get {
                return _client;
            }
        }
    /// <summary>
    ///Gets and sets the users Username
    /// </summary>
       public string Username {
            get {
                return _user;
            }
            set {
                _user = value;
            }
        }
        /// <summary>
        /// Gets and sets the users hostname
        /// </summary>
        public string Host {
            get {
                return _host;
            }
            set {
                _host = value;
            }
        }
        /// <summary>
        /// Gets if this user is in the internal userlist. Use AddMe and DeleteMe to change
        /// </summary>
        public bool IsInList {
            get {
                return users.Contains(this);
            }
        }
        private User(string nick, Client clnt) {
            _nick = nick;
            _client = clnt;
        }
        private User(UserInfo info, Client clnt) {
            _nick = info.nick;
            _user = info.user;
            _host = info.host;
            _client = clnt;
        }
        static List<User> users = new List<User>();
        /// <summary>
        /// Gets a user from the userlist, or creates a new object for them outside of the list
        /// </summary>
        /// <param name="nick">Nick to get user of</param>
        /// <param name="clnt">Client</param>
        /// <returns>User</returns>
        public static User GetUser(string nick, Client clnt) {
            lock (users) {
                foreach (User u in users) {
                    if (u.Client == clnt && String.Compare(u.Nick,nick,true) == 0)
                        return u;
                }
            }
            return new User(nick, clnt);
        }

        /// <summary>
        /// Gets a user from the userlist, or creates a new object for them outside of the list
        /// </summary>
        /// <param name="info">Info of user to get</param>
        /// <param name="clnt">Client</param>
        /// <returns>User</returns>
        public static User GetUser(UserInfo info, Client clnt) {
            lock (users) {
                foreach (User u in users) {
                    if (u.Client == clnt && String.Compare(u.Nick, info.nick, true) == 0) {
                        u.Host = info.host;
                        u.Nick = info.nick;
                        return u;
                    }
                }
            }
            return new User(info, clnt);
        }
        /// <summary>
        /// Gets the Me user for the given client. Represents the library client.
        /// </summary>
        /// <param name="clnt">Client</param>
        /// <returns>User</returns>
        public static User GetMe(Client clnt) {
            User me;
            lock (mes) {
                if (mes.TryGetValue(clnt, out me)) {
                    return me;
                }
                else {
                    me = new User(clnt.Nick, clnt);
                    me.Username = clnt.Username;
                    mes.Add(clnt, me);
                }
            }
            return me;
        }

        /// <summary>
        /// Adds to userlist
        /// </summary>
        public void AddMe() {
            lock (users) {
                if (!users.Contains(this))
                    users.Add(this);
            }
        }
        /// <summary>
        /// Removes from userlist
        /// </summary>
        public void DelMe() {
            lock (users) {
                if (users.Contains(this))
                    users.Remove(this);
            }
        }
        /// <summary>
        /// Returns user's nickname
        /// </summary>
        /// <returns>Nickname</returns>
        public override string ToString() {
            return Nick;
        }
        /// <summary>
        /// Is this user on this channel
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        public bool IsOn(Channel channel) {
            return channel.GetUsers().Contains(this);
        }
        /// <summary>
        /// Gets access of this user on this channel
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        public ChannelAccess GetAccess(Channel channel) {
            return channel.GetAccess(this);
        }

        /// <summary>
        /// Sends a private message to this user
        /// </summary>
        /// <param name="message">message to send</param>
        public void SendMessage(string message) {
            Client.Send("PRIVMSG {0} :{1}", Nick, message);
        }
        /// <summary>
        /// Sends a notice to this user
        /// </summary>
        /// <param name="message"></param>
        public void SendNotice(string message)
        {
            Client.Send("NOTICE {0} :{1}", Nick, message);
        }
        /// <summary>
        /// Sends a formatted private message to this user
        /// </summary>
        /// <param name="format">Format</param>
        /// <param name="arg">Format Arguments</param>
        public void SendMessage(string format, params object[] arg) {
            SendMessage(String.Format(format, arg));

        }
        /// <summary>
        /// Sends a formatted notice to this user
        /// </summary>
        /// <param name="format">Format</param>
        /// <param name="arg">Format Arguments</param>
        public void SendNotice(string format, params object[] arg)
        {
            SendNotice(String.Format(format, arg));

        }
    }
}
